﻿namespace Legend.Core.Tests.Integration.Threading
{
    using System;
    using System.Diagnostics;
    using System.Threading;
    using Legend.Threading;
    using NUnit.Framework;

    [TestFixture]
    public class SchedulerWithSystemTimersTimer
    {
        private Scheduler scheduler;

        [SetUp]
        public void SetUp()
        {
            this.OnSetUp();
        }

        protected virtual void OnSetUp()
        {
            var synchronizationManager = new MonitorSynchronizationManager(new object());
            TimerFactory timerFactory = x => new TimerAdapter(new System.Timers.Timer((double)x.TotalMilliseconds));
            this.scheduler = new Scheduler(timerFactory, synchronizationManager, () => DateTime.Now);
        }

        [Test]
        public void should_callback_immediately_when_()
        {
            bool wasCalled = false;

            scheduler.Schedule(() => wasCalled = true, DateTime.Now);

            Thread.Sleep(100);

            Assert.That(wasCalled, Is.True);
        }

        [Test]
        public void should_callback_at_time_specified()
        {
            DateTime callbackTime = DateTime.Now.AddSeconds(2);
            DateTime actualCallbackTime = DateTime.MinValue;
            scheduler.Schedule(() => actualCallbackTime = DateTime.Now, callbackTime);

            while (actualCallbackTime == DateTime.MinValue)
            {
                Debug.WriteLine("Waiting... " + DateTime.Now.ToString());
                Thread.Sleep(2000);
            }

            Debug.WriteLine("Diff: " + Math.Abs(callbackTime.Subtract(actualCallbackTime).TotalMilliseconds).ToString() + " milliseconds.");
            Assert.IsTrue(Math.Abs(callbackTime.Subtract(actualCallbackTime).TotalMilliseconds) < 200);
        }

        [Test]
        public void should_callback_at_all_times_specified()
        {
            int loops = 50;
            var startTime = DateTime.Now;
            var numberOfCallbacksMade = 0;

            for (int i = 0; i < loops; i++)
            {
                scheduler.Schedule(() =>
                    {
                        Debug.WriteLine(DateTime.Now);
                        numberOfCallbacksMade++;
                    }, startTime.AddSeconds(i * 2));
            }

            while (numberOfCallbacksMade < loops)
            {
                Thread.Sleep(50);
            }
        }
    }
}